package com.browan.constellation.weibo;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class HttpClient
{

	/**
	 * User-Agent
	 */
	public static final String USER_AGENT_VALUE = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; EmbeddedWB 14.52 from: http://www.bsalsa.com/ EmbeddedWB 14.52; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1; .NET CLR 1.0.3705; .NET CLR 3.0.04506.30)";

	/**
	 * 命令分隔符
	 */
	public static final String HTTP_CLIENT_CMD_SPLITOR = "@@";

	/**
	 * POST 参数分隔符
	 */
	public static final String POST_PARAMETER_SPLITOR = "&";

	/**
	 * POST 参数值分隔符
	 */
	private static final String POST_PARAMETER_KV_SPLITOR = "=";

	/**
	 * 默认Cookie 内容
	 */
	private static String cookie;

	/**
	 * 从HTML头中找到编码字段
	 */
	private static Pattern CONTENT_TYPE_CHARSET_PATTERN = Pattern.compile("charset=([-_a-zA-Z0-9]*)");

	/**
	 * Cookie 表
	 */
	@SuppressWarnings("unused")
	private static Map<String, String> cookieMap = new HashMap<String, String>();

	/**
	 * 初始HttpClient 的一个新实例
	 */
	public HttpClient()
	{

	}

	/**
	 * GET 方法请求给定URL，并且返HTTP 响应的内容
	 * 
	 * @param url
	 *            要请求的 URL
	 * @param keepCookie
	 *            是否保存 Cookie 信息
	 * @return 给定 URL 返回的响应
	 */
	public String getMethod(String url, boolean keepCookie)
	{
		return getMethod(url, null, keepCookie);
	}

	/**
	 * GET 方法请求给定URL，并且返HTTP 响应的内容
	 * 
	 * @param url
	 *            要请求的 URL
	 * @param heads
	 *            请求包含HTTP 头
	 * @param keepCookie
	 *            是否保存 Cookie 信息
	 * @return 给定 URL 返回的响应
	 */
	public String getMethod(String url, Map<String, String> heads, boolean keepCookie)
	{
		if (url == null || url.length() == 0)
		{
			return "Requst url could not be null or empty.";
		}

		StringBuffer result = new StringBuffer();
		BufferedReader httpBufferedReader = null;
		try
		{
			HttpURLConnection httpURLConnection = getHttpURLConnection(url);
			if (heads != null)
			{
				for (Iterator<Entry<String, String>> iter = heads.entrySet().iterator(); iter.hasNext();)
				{
					Entry<String, String> entry = iter.next();
					httpURLConnection.setRequestProperty(entry.getKey(), entry.getValue());
				}
			}
			// Set request properties.
			settingHttpRequestHeader(httpURLConnection);
			httpURLConnection.setRequestMethod("GET");
			httpURLConnection.setDoInput(true);
			// Getting or setting cookie
			gettingOrSettingCookie(httpURLConnection, keepCookie);

			httpURLConnection.connect();

			InputStream httpInputStream = httpURLConnection.getInputStream();
			String encoding = httpURLConnection.getContentEncoding();
			if (encoding == null)
			{
				String contentType = httpURLConnection.getContentType();
				int i = contentType.indexOf("charset=");
				if (i != -1)
				{
					encoding = contentType.substring(i + 8);
				}
			}

			if (encoding != null)
			{
				httpBufferedReader = new BufferedReader(new InputStreamReader(httpInputStream, encoding));
			}
			else
			{
				httpBufferedReader = new BufferedReader(new InputStreamReader(httpInputStream));
			}
			result.append(readBufferedContent(httpBufferedReader));
		}
		catch (IOException e)
		{
			return null;
		}
		finally
		{
			if (null != httpBufferedReader)
			{
				close(httpBufferedReader);
			}

		}
		return result.toString();
	}

	/**
	 * POST 方法请求给定URL，并且返HTTP 响应的内容
	 * 
	 * @param url
	 *            要请求的 URL
	 * @param parameters
	 *            要发送的参数
	 * @param keepCookie
	 *            是否保存 Cookie 信息
	 * @return 给定 URL 返回的响应
	 * @throws Exception
	 */
	public String postMethod(String url, Map<String, String> parameters, boolean keepCookie) throws Exception
	{
		return postMethod(url, null, parameters, keepCookie);
	}

	public String postMethod(String url, Map<String, String> parameters, Map<String, String> header, String encoding)
			throws IOException
	{

		String postResponse = null;
		HttpURLConnection httpURLConnection = null;
		OutputStream httpOutputStream = null;
		try
		{
			// Build post parameters string
			StringBuffer postParams = new StringBuffer();
			if (parameters != null)
			{
				int index = 0;
				for (Iterator<Entry<String, String>> iter = parameters.entrySet().iterator(); iter.hasNext(); index++)
				{
					Entry<String, String> entry = iter.next();
					postParams.append(index != 0 ? POST_PARAMETER_SPLITOR : "");
					postParams.append(entry.getKey());
					postParams.append(POST_PARAMETER_KV_SPLITOR);
					postParams.append(entry.getValue());
				}
			}
			httpURLConnection = getHttpURLConnection(url);
			// Set request properties.
			settingHttpRequestHeader(httpURLConnection);
			// Set request method with 'POST'
			httpURLConnection.setRequestMethod("POST");
			httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			// application/x-www-form-urlencoded;charset=UTF-8
			// Set connection output is true.
			httpURLConnection.setDoOutput(true);

			httpURLConnection.setRequestProperty("Content-Length", String.valueOf(postParams.toString().length()));

			// Get Http output stream

			// int recode = httpURLConnection.getResponseCode();
			// System.out.println(recode);
			// System.out.println(httpURLConnection.getResponseCode());

			httpOutputStream = httpURLConnection.getOutputStream();
			httpOutputStream.write(postParams.toString().getBytes());
			// Getting or setting cookie

			if (null == encoding)
			{
				String contentType = httpURLConnection.getContentType();
				Matcher matcher = CONTENT_TYPE_CHARSET_PATTERN.matcher(contentType);
				if (matcher.find())
				{
					encoding = matcher.group(1);
				}
			}
			InputStream inputStream = httpURLConnection.getInputStream();
			ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
			byte[] buffer = new byte[8192];
			int size = -1;
			while ((size = inputStream.read(buffer)) != -1)
			{
				byteStream.write(buffer, 0, size);
			}
			byte[] data = byteStream.toByteArray();
			if (encoding != null)
			{
				postResponse = new String(data, encoding);
			}
			else
			{
				postResponse = new String(data, "utf-8");
			}
		}
		finally
		{
			if (null != httpOutputStream)
				try
				{
					httpOutputStream.close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
		}

		return postResponse;

	}

	public String postMethod(String url, Map<String, String> parameters, String encoding) throws IOException
	{

		String postResponse = null;
		HttpURLConnection httpURLConnection = null;
		OutputStream httpOutputStream = null;
		try
		{
			// Build post parameters string
			StringBuffer postParams = new StringBuffer();
			if (parameters != null)
			{
				int index = 0;
				for (Iterator<Entry<String, String>> iter = parameters.entrySet().iterator(); iter.hasNext(); index++)
				{
					Entry<String, String> entry = iter.next();
					postParams.append(index != 0 ? POST_PARAMETER_SPLITOR : "");
					postParams.append(entry.getKey());
					postParams.append(POST_PARAMETER_KV_SPLITOR);
					postParams.append(entry.getValue());
				}
			}
			httpURLConnection = getHttpURLConnection(url);
			// Set request properties.
			settingHttpRequestHeader(httpURLConnection);
			// Set request method with 'POST'
			httpURLConnection.setRequestMethod("POST");
			httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			// application/x-www-form-urlencoded;charset=UTF-8
			// Set connection output is true.
			httpURLConnection.setDoOutput(true);

			httpURLConnection.setRequestProperty("Content-Length", String.valueOf(postParams.toString().length()));

			// Get Http output stream

			// int recode = httpURLConnection.getResponseCode();
			// System.out.println(recode);
			// System.out.println(httpURLConnection.getResponseCode());

			httpOutputStream = httpURLConnection.getOutputStream();
			httpOutputStream.write(postParams.toString().getBytes());
			// Getting or setting cookie

			if (null == encoding)
			{
				String contentType = httpURLConnection.getContentType();
				Matcher matcher = CONTENT_TYPE_CHARSET_PATTERN.matcher(contentType);
				if (matcher.find())
				{
					encoding = matcher.group(1);
				}
			}
			InputStream inputStream = httpURLConnection.getInputStream();
			ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
			byte[] buffer = new byte[8192];
			int size = -1;
			while ((size = inputStream.read(buffer)) != -1)
			{
				byteStream.write(buffer, 0, size);
			}
			byte[] data = byteStream.toByteArray();
			if (encoding != null)
			{
				postResponse = new String(data, encoding);
			}
			else
			{
				postResponse = new String(data, "utf-8");
			}
		}
		finally
		{
			if (null != httpOutputStream)
				try
				{
					httpOutputStream.close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
		}

		return postResponse;

	}

	/**
	 * POST 方法请求给定URL，并且返HTTP 响应的内容
	 * 
	 * @param url
	 *            要请求的 URL
	 * @param parameters
	 *            要发送的参数
	 * @param keepCookie
	 *            是否保存 Cookie 信息
	 * @return 给定 URL 返回的响应
	 * @throws Exception
	 */
	public String postMethod(String url, Map<String, String> heads, Map<String, String> parameters, boolean keepCookie)
			throws Exception
	{
		// StringBuffer httpResponse = new StringBuffer();
		String postResponse = null;
		HttpURLConnection httpURLConnection = null;
		OutputStream httpOutputStream = null;
		InputStream inputStream = null;
		try
		{
			// Build post parameters string
			StringBuffer postParams = new StringBuffer();
			if (parameters != null)
			{
				int index = 0;
				for (Iterator<Entry<String, String>> iter = parameters.entrySet().iterator(); iter.hasNext(); index++)
				{
					Entry<String, String> entry = iter.next();
					postParams.append(index != 0 ? POST_PARAMETER_SPLITOR : "");
					postParams.append(entry.getKey());
					postParams.append(POST_PARAMETER_KV_SPLITOR);
					postParams.append(entry.getValue());
				}
			}
			httpURLConnection = getHttpURLConnection(url);
			// Set request properties.
			settingHttpRequestHeader(httpURLConnection);
			if (heads != null)
			{
				int index = 0;
				for (Iterator<Entry<String, String>> iter = heads.entrySet().iterator(); iter.hasNext(); index++)
				{
					Entry<String, String> entry = iter.next();
					httpURLConnection.setRequestProperty(entry.getKey(), entry.getValue());
				}
			}
			// Set request method with 'POST'
			httpURLConnection.setRequestMethod("POST");
			httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			// application/x-www-form-urlencoded;charset=UTF-8
			// Set connection output is true.
			httpURLConnection.setDoOutput(true);

			httpURLConnection.setRequestProperty("Content-Length", String.valueOf(postParams.toString().length()));

			gettingOrSettingCookie(httpURLConnection, keepCookie);

			// Get Http output stream
			httpOutputStream = httpURLConnection.getOutputStream();
			httpOutputStream.write(postParams.toString().getBytes());
			// Getting or setting cookie

			httpOutputStream.flush();

			// String contentType = httpURLConnection.getContentType();
			// String encoding = null;
			// Matcher matcher =
			// CONTENT_TYPE_CHARSET_PATTERN.matcher(contentType);
			// if (matcher.find())
			// {
			// encoding = matcher.group(1);
			// }

			int code = httpURLConnection.getResponseCode();

			if (code == 400)
			{
				// 发送重复的东西了

				postResponse = String.valueOf(code);
			}
			else
			{
				inputStream = httpURLConnection.getInputStream();
				ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
				byte[] buffer = new byte[8192];
				int size = -1;
				while ((size = inputStream.read(buffer)) != -1)
				{
					byteStream.write(buffer, 0, size);
				}
				byte[] data = byteStream.toByteArray();
				// if (encoding != null)
				// {
				// postResponse = new String(data, encoding);
				// }
				// else
				// {
				postResponse = new String(data, "utf-8");
				// }
			}
		}
		catch (Exception e)
		{
			throw e;
		}
		finally
		{
			if (null != httpOutputStream)
			{
				httpOutputStream.close();
				httpOutputStream = null;
			}

			if (null != inputStream)
			{
				inputStream.close();
				inputStream = null;
			}

		}

		return postResponse;
	}

	/**
	 * POST 方法请求给定URL，并且返HTTP 响应的内容
	 * 
	 * @param url
	 *            要请求的 URL
	 * @param soapEnvelope
	 *            要发送的 SOAP 请求
	 * @param keepCookie
	 *            是否保存 Cookie 信息
	 * @return 给定 URL 返回的响应
	 */
	public String postSoap(String url, String soapAction, String soapEnvelope)
	{

		StringBuffer httpResponse = new StringBuffer();

		HttpURLConnection httpURLConnection = null;
		OutputStream httpOutputStream = null;
		try
		{
			httpURLConnection = getHttpURLConnection(url);
			// Set request method with 'POST'
			httpURLConnection.setRequestMethod("POST");
			httpURLConnection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
			// Set connection output is true.
			httpURLConnection.setDoOutput(true);
			byte[] buffer = soapEnvelope.getBytes("utf8");
			// httpURLConnection.setRequestProperty("Content-Length",
			// String.valueOf(buffer.length));
			httpURLConnection.setRequestProperty("Content-Length", String.valueOf(buffer.length));
			httpURLConnection.setRequestProperty("SOAPAction", soapAction);
			// Get Http output stream
			httpOutputStream = httpURLConnection.getOutputStream();
			httpOutputStream.write(buffer);
			// Getting or setting cookie
			gettingOrSettingCookie(httpURLConnection, false);

			BufferedReader httpBufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection
					.getInputStream()));
			httpResponse.append(readBufferedContent(httpBufferedReader));
		}
		catch (Exception e)
		{
			return null;
		}
		finally
		{
			try
			{
				if (httpOutputStream != null)
				{
					httpOutputStream.close();
				}
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
		return httpResponse != null ? httpResponse.toString() : null;
	}

	/**
	 * Setting HTTP request header properties
	 * 
	 * @param httpURLConnection
	 */
	private void settingHttpRequestHeader(HttpURLConnection httpURLConnection)
	{
		if (httpURLConnection == null)
			return;
		httpURLConnection.setRequestProperty("User-Agent", USER_AGENT_VALUE);
		// TODO setting some other properties here . . .
	}

	/**
	 * Get HttpURLConnection by specified url string.
	 * 
	 * @param url
	 * @return
	 * @throws IOException
	 */
	private HttpURLConnection getHttpURLConnection(String url) throws IOException
	{
		URL urlObj = new URL(url);
		URLConnection urlConnection = urlObj.openConnection();
		if (urlConnection instanceof HttpURLConnection)
			return (HttpURLConnection) urlConnection;
		throw new MalformedURLException();
	}

	/**
	 * Read bufferedReader buffered content.
	 * 
	 * @param bufferedReader
	 * @return
	 */
	private String readBufferedContent(BufferedReader bufferedReader)
	{
		if (bufferedReader == null)
			return null;
		StringBuffer result = new StringBuffer();
		String line = null;
		try
		{
			while ((line = bufferedReader.readLine()) != null)
			{
				result.append(line);
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
			return null;
		}
		return result.toString();
	}

	/**
	 * 解析查询字符串
	 * 
	 * @param parameterString
	 *            要解析的查询字符串
	 * @return
	 */
	public static Map<String, String> parsePostParameters(String parameterString)
	{
		if (parameterString == null || parameterString.length() == 0)
			return null;
		Map<String, String> result = new HashMap<String, String>();

		// only one parameter key-value pair
		if (parameterString.indexOf(POST_PARAMETER_SPLITOR) == -1)
		{
			if (parameterString.indexOf(POST_PARAMETER_KV_SPLITOR) != -1)
				result.put(parameterString.split(POST_PARAMETER_KV_SPLITOR)[0], parameterString
						.split(POST_PARAMETER_KV_SPLITOR)[1]);
		}
		else
		{
			String[] keyValues = parameterString.split(POST_PARAMETER_SPLITOR);
			for (int i = 0; i < keyValues.length; i++)
			{
				String keyValue = keyValues[i];
				result.put(keyValue.split(POST_PARAMETER_KV_SPLITOR)[0], keyValue.split(POST_PARAMETER_KV_SPLITOR)[1]);
			}
		}
		return result;
	}

	/**
	 * Get or set cookie.
	 * 
	 * @param httpURLConnection
	 * @param keepCookie
	 */
	private void gettingOrSettingCookie(HttpURLConnection httpURLConnection, boolean keepCookie)
	{
		if (!keepCookie)
			return;
		// Getting or setting cookie.
		if (cookie == null || cookie.length() == 0)
		{
			Map<String, List<String>> heads = httpURLConnection.getHeaderFields();
			if (heads == null)
				return;
			String setCookie = "";
			List<String> list = heads.get("set-cookie");
			for (String name : list)
			{
				int index = name.indexOf(";");
				if (index != -1)
				{
					setCookie += name.substring(0, index + 1);
				}
				else
				{
					setCookie += name + ";";
				}
			}
			if (setCookie != "")
			{
				cookie = setCookie;// setCookie.substring(0,
				// setCookie.indexOf(";"));
			}
		}
		else if (cookie != null)
		{
			httpURLConnection.setRequestProperty("Cookie", cookie);
		}
	}

	/**
	 * Download data from url
	 * 
	 * @param url
	 * @return
	 */
	public static byte[] fetchData(String url)
	{
		byte[] data = null;

		if (url != null)
		{
			InputStream is = null;

			try
			{
				// Open a new URL and get the InputStream to load data from it.
				URL url2 = new URL(url);
				URLConnection conn = url2.openConnection();
				conn.setConnectTimeout(0);
				conn.setReadTimeout(0);
				conn.connect();
				is = conn.getInputStream();
				byte[] tmp = new byte[2048];
				ByteArrayOutputStream stream = new ByteArrayOutputStream();
				int len = -1;
				while ((len = is.read(tmp)) != -1)
				{
					stream.write(tmp, 0, len);
				}
				data = stream.toByteArray();
				// Note we do not want to save the image to the file system.
				// AdMob
				// servers may use the download for accounting and optimization
				// purposes.
			}
			catch (Exception e)
			{
			}
			finally
			{
				if (is != null)
				{
					try
					{
						is.close();
					}
					catch (IOException e)
					{
						// Ignore and continue.
					}
				}
			}
		}
		return data;
	}

	public void close(Object stream)
	{
		if (null != stream)
		{

			if (stream instanceof Closeable)
			{
				try
				{
					((Closeable) stream).close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}

			}
		}
	}

}